package com.app.library.utils

import java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.io.File
import java.io.IOException
import java.util.*

/**
 * 多开检测
 */
object CheckVirtual {

    private const val TAG = "CheckVirtual"

    val isRunInVirtual: Boolean
        get() {
            val filter = uidStrFormat
            val result = exec("ps")
            if (result == null || result.isEmpty()) {
                return false
            }
            val lines = result.split("\n").toTypedArray()
            if (lines.isEmpty()) {
                return false
            }
            var exitDirCount = 0
            for (i in lines.indices) {
                if (lines[i].contains(filter!!)) {
                    val pkgStartIndex = lines[i].lastIndexOf(" ")
                    val processName = lines[i].substring(
                        if (pkgStartIndex <= 0) 0 else pkgStartIndex + 1,
                        lines[i].length
                    )
                    val dataFile = File(
                        String.format(
                            "/data/data/%s",
                            processName, Locale.CHINA
                        )
                    )
                    if (dataFile.exists()) {
                        exitDirCount++
                    }
                }
            }
            return exitDirCount > 1
        }

    private fun exec(command: String): String? {
        var bufferedOutputStream: BufferedOutputStream? = null
        var bufferedInputStream: BufferedInputStream? = null
        var process: Process? = null
        return try {
            process = Runtime.getRuntime().exec("sh")
            bufferedOutputStream = BufferedOutputStream(process.outputStream)
            bufferedInputStream = BufferedInputStream(process.inputStream)
            bufferedOutputStream.write(command.toByteArray())
            bufferedOutputStream.write('\n'.code)
            bufferedOutputStream.flush()
            bufferedOutputStream.close()
            process.waitFor()
            getStrFromBufferInputSteam(bufferedInputStream)
        } catch (e: Exception) {
            null
        } finally {
            if (bufferedOutputStream != null) {
                try {
                    bufferedOutputStream.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
            if (bufferedInputStream != null) {
                try {
                    bufferedInputStream.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
            process?.destroy()
        }
    }

    private fun getStrFromBufferInputSteam(bufferedInputStream: BufferedInputStream?): String {
        if (null == bufferedInputStream) {
            return ""
        }
        val BUFFER_SIZE = 512
        val buffer = ByteArray(BUFFER_SIZE)
        val result = StringBuilder()
        try {
            while (true) {
                val read = bufferedInputStream.read(buffer)
                if (read > 0) {
                    result.append(String(buffer, 0, read))
                }
                if (read < BUFFER_SIZE) {
                    break
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return result.toString()
    }

    private val uidStrFormat: String?
        get() {
            var filter = exec("cat /proc/self/cgroup")
            if (filter == null || filter.isEmpty()) {
                return null
            }
            val uidStartIndex = filter.lastIndexOf("uid")
            var uidEndIndex = filter.lastIndexOf("/pid")
            if (uidStartIndex < 0) {
                return null
            }
            if (uidEndIndex <= 0) {
                uidEndIndex = filter.length
            }
            filter = filter.substring(uidStartIndex + 4, uidEndIndex)
            return try {
                val strUid = filter.replace("\n".toRegex(), "")
                if (isNumber(strUid)) {
                    val uid = Integer.valueOf(strUid)
                    filter = String.format("u0_a%d", uid - 10000)
                    return filter
                }
                null
            } catch (e: Exception) {
                e.printStackTrace()
                null
            }
        }

    private fun isNumber(str: String?): Boolean {
        if (str == null || str.isEmpty()) {
            return false
        }
        for (element in str) {
            if (!Character.isDigit(element)) {
                return false
            }
        }
        return true
    }
}